[XEN] Skip shadowing of guest PTE writes when known to be safe
authorTim Deegan <Tim.Deegan@xensource.com>
Wed, 20 Dec 2006 11:54:57 +0000 (11:54 +0000)
committerTim Deegan <Tim.Deegan@xensource.com>
Wed, 20 Dec 2006 11:54:57 +0000 (11:54 +0000)
That is, when the guest replaces a not-present pte with another one
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
xen/arch/x86/mm/shadow/multi.c
xen/arch/x86/mm/shadow/private.h
xen/include/asm-x86/shadow.h

index 159a357b4a31ce2a1bfd29500922de32aad09519..32af02266877b163d77550328a0bdb2c9451ac8d 100644 (file)
@@ -3839,12 +3839,43 @@ static inline void * emulate_map_dest(struct vcpu *v,
     return NULL;
 }
 
+static int safe_not_to_verify_write(mfn_t gmfn, void *dst, void *src, 
+                                    int bytes)
+{
+#if (SHADOW_OPTIMIZATIONS & SHOPT_SKIP_VERIFY)
+    struct page_info *pg = mfn_to_page(gmfn);
+    if ( !(pg->shadow_flags & SHF_32) 
+         && bytes == 4 
+         && ((unsigned long)dst & 3) == 0 )
+    {
+        /* Not shadowed 32-bit: aligned 64-bit writes that leave the
+         * present bit unset are safe to ignore. */
+        if ( (*(u64*)src & _PAGE_PRESENT) == 0 
+             && (*(u64*)dst & _PAGE_PRESENT) == 0 )
+            return 1;
+    }
+    else if ( !(pg->shadow_flags & (SHF_PAE|SHF_64)) 
+              && bytes == 8 
+              && ((unsigned long)dst & 7) == 0 )
+    {
+        /* Not shadowed PAE/64-bit: aligned 32-bit writes that leave the
+         * present bit unset are safe to ignore. */
+        if ( (*(u32*)src & _PAGE_PRESENT) == 0 
+             && (*(u32*)dst & _PAGE_PRESENT) == 0 )
+            return 1;        
+    }
+#endif
+    return 0;
+}
+
+
 int
 sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src,
                       u32 bytes, struct sh_emulate_ctxt *sh_ctxt)
 {
     mfn_t mfn;
     void *addr;
+    int skip;
 
     if ( vaddr & (bytes-1) )
         return X86EMUL_UNHANDLEABLE;
@@ -3855,8 +3886,9 @@ sh_x86_emulate_write(struct vcpu *v, unsigned long vaddr, void *src,
     if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
         return X86EMUL_PROPAGATE_FAULT;
 
+    skip = safe_not_to_verify_write(mfn, addr, src, bytes);
     memcpy(addr, src, bytes);
-    shadow_validate_guest_pt_write(v, mfn, addr, bytes);
+    if ( !skip ) shadow_validate_guest_pt_write(v, mfn, addr, bytes);
 
     /* If we are writing zeros to this page, might want to unshadow */
     if ( likely(bytes >= 4) && (*(u32 *)addr == 0) )
@@ -3875,7 +3907,7 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
     mfn_t mfn;
     void *addr;
     unsigned long prev;
-    int rv = X86EMUL_CONTINUE;
+    int rv = X86EMUL_CONTINUE, skip;
 
     ASSERT(shadow_locked_by_me(v->domain));
     ASSERT(bytes <= sizeof(unsigned long));
@@ -3886,6 +3918,8 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
     if ( (addr = emulate_map_dest(v, vaddr, sh_ctxt, &mfn)) == NULL )
         return X86EMUL_PROPAGATE_FAULT;
 
+    skip = safe_not_to_verify_write(mfn, &new, &old, bytes);
+
     switch ( bytes )
     {
     case 1: prev = cmpxchg(((u8 *)addr), old, new);  break;
@@ -3898,7 +3932,9 @@ sh_x86_emulate_cmpxchg(struct vcpu *v, unsigned long vaddr,
     }
 
     if ( prev == old )
-        shadow_validate_guest_pt_write(v, mfn, addr, bytes);
+    {
+        if ( !skip ) shadow_validate_guest_pt_write(v, mfn, addr, bytes);
+    }
     else
         rv = X86EMUL_CMPXCHG_FAILED;
 
@@ -3924,7 +3960,7 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr,
     mfn_t mfn;
     void *addr;
     u64 old, new, prev;
-    int rv = X86EMUL_CONTINUE;
+    int rv = X86EMUL_CONTINUE, skip;
 
     ASSERT(shadow_locked_by_me(v->domain));
 
@@ -3936,10 +3972,13 @@ sh_x86_emulate_cmpxchg8b(struct vcpu *v, unsigned long vaddr,
 
     old = (((u64) old_hi) << 32) | (u64) old_lo;
     new = (((u64) new_hi) << 32) | (u64) new_lo;
+    skip = safe_not_to_verify_write(mfn, &new, &old, 8);
     prev = cmpxchg(((u64 *)addr), old, new);
 
     if ( prev == old )
-        shadow_validate_guest_pt_write(v, mfn, addr, 8);
+    {
+        if ( !skip ) shadow_validate_guest_pt_write(v, mfn, addr, 8);
+    }
     else
         rv = X86EMUL_CMPXCHG_FAILED;
 
index 6fab2789f9460cb5266bbbae2fb4bc5ea279ba57..62a6364c39058577b8fb3e226990ca87f4039ac4 100644 (file)
@@ -249,6 +249,10 @@ static inline int sh_type_is_pinnable(struct vcpu *v, unsigned int t)
 #define SHF_L3_64   (1u << SH_type_l3_64_shadow)
 #define SHF_L4_64   (1u << SH_type_l4_64_shadow)
 
+#define SHF_32  (SHF_L1_32|SHF_FL1_32|SHF_L2_32)
+#define SHF_PAE (SHF_L1_PAE|SHF_FL1_PAE|SHF_L2_PAE|SHF_L2H_PAE)
+#define SHF_64  (SHF_L1_64|SHF_FL1_64|SHF_L2_64|SHF_L3_64|SHF_L4_64)
+
 /* Used for hysteresis when automatically unhooking mappings on fork/exit */
 #define SHF_unhooked_mappings (1u<<31)
 
index 94591e6dad3303423705137d138fc35891c93e7d..4b9094cb7c5054e1f30e5495f6e6ade4c69e8803 100644 (file)
@@ -159,8 +159,9 @@ extern int shadow_audit_enable;
 #define SHOPT_FAST_FAULT_PATH     0x04  /* Fast-path MMIO and not-present */
 #define SHOPT_PREFETCH            0x08  /* Shadow multiple entries per fault */
 #define SHOPT_LINUX_L3_TOPLEVEL   0x10  /* Pin l3es on early 64bit linux */
+#define SHOPT_SKIP_VERIFY         0x20  /* Skip PTE v'fy when safe to do so */
 
-#define SHADOW_OPTIMIZATIONS      0x1f
+#define SHADOW_OPTIMIZATIONS      0x3f
 
 
 /* With shadow pagetables, the different kinds of address start